package com.xyzwps.paimon.furina.modules.post.entity

import com.fasterxml.jackson.core.type.TypeReference
import com.xyzwps.paimon.furina.common.JSON
import com.xyzwps.paimon.furina.common.value.DedupKey
import kotlinx.datetime.LocalDateTime
import org.jetbrains.exposed.dao.id.LongIdTable
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.ResultRow
import org.jetbrains.exposed.sql.json.json
import org.jetbrains.exposed.sql.kotlin.datetime.datetime

data class Post(
    val id: Long,
    val userId: Long,
    val collectionId: Long,
    val title: String,
    val type: PostType,
    val content: String,
    val tagIds: List<Long>,
    val createTime: LocalDateTime,
    val deleteTime: LocalDateTime?,
    val updateTime: LocalDateTime,
) {

    constructor(row: ResultRow) : this(
        id = row[TABLE.id].value,
        userId = row[TABLE.userId],
        collectionId = row[TABLE.collectionId],
        title = row[TABLE.title],
        type = row[TABLE.type],
        content = row[TABLE.content],
        tagIds = row[TABLE.tagIds],
        createTime = row[TABLE.createTime],
        deleteTime = row[TABLE.deleteTime],
        updateTime = row[TABLE.updateTime],
    )

    companion object {
        const val TITLE_MAX_LEN = 200
        const val CONTENT_MAX_LEN = 20000

        private object LONG_LIST_REF : TypeReference<List<Long>>()

        object TABLE : LongIdTable("post", columnName = "id") {
            val userId: Column<Long> = long("user_id")
            val collectionId: Column<Long> = long("collection_id")
            val title: Column<String> = varchar("title", TITLE_MAX_LEN)
            val type: Column<PostType> = customEnumeration(
                "type",
                "ENUM('MD', 'TXT')",
                fromDb = { PostType.valueOf(it as String) },
                toDb = { it.name })
            val content: Column<String> = text("content")
            val tagIds: Column<List<Long>> = json("tag_ids",
                serialize = JSON::stringify,
                deserialize = fun(str: String?): List<Long> =
                    if (str.isNullOrEmpty()) emptyList()
                    else JSON.parse(str, LONG_LIST_REF)
            )
            val dedupKey: Column<String> = varchar("dedup_key", DedupKey.MAX_LEN)
            val createTime: Column<LocalDateTime> = datetime("create_time")
            val deleteTime: Column<LocalDateTime?> = datetime("delete_time").nullable()
            val updateTime: Column<LocalDateTime> = datetime("update_time")

            init {
                index(customIndexName = "idx_collection_posts", columns = arrayOf(collectionId))
                uniqueIndex(customIndexName = "uk_user_post_dedup_key", userId, dedupKey)
            }
        }
    }
}
